#pragma once
#include "compile.hpp"
#include "runner.hpp"
#include "../comm/log.hpp"
#include "../comm/util.hpp"
#include <signal.h>
#include <unistd.h>
#include <jsoncpp/json/json.h>
#include "../comm/httplib.h"

namespace ns_compile_and_run
{
    using namespace ns_log;
    using namespace ns_util;//展开命名空间
    using namespace ns_compiler;
    using namespace ns_runner;

    class CompileAndRun
    {
    public:
        static void RemoveTempFile(const std::string&file_name)
        {
            //如果是编译报错只有 .cpp.compile_error,exe。如果是运行报错则会多有stdin,stdout,stderr
            std::string _src=PathUtil::Src(file_name);
            if(FileUtil::IsFileExist(_src)) unlink(_src.c_str());

            std::string _execute=PathUtil::Exe(file_name);
            if(FileUtil::IsFileExist(_execute)) unlink(_execute.c_str());

            std::string _compiler_error=PathUtil::CompileError(file_name);
            if(FileUtil::IsFileExist(_compiler_error)) unlink(_compiler_error.c_str());

            std::string _stdin=PathUtil::Stdin(file_name);
            if(FileUtil::IsFileExist(_stdin)) unlink(_stdin.c_str());

            std::string _stdout=PathUtil::Stdout(file_name);
            if(FileUtil::IsFileExist(_stdout)) unlink(_stdout.c_str());

            std::string _stderr=PathUtil::Stderr(file_name);
            if(FileUtil::IsFileExist(_stderr)) unlink(_stderr.c_str());
        }

    //输入：
    //code ：用户提交的代码。
    //input: 用户提交代码对应的输入
    //cpu_limit: 时间限制
    //mem_limit :空间限制

    //服务器的回复，输出
    //status: 状态码
    //reason: 请求结果,输出


    //in_json {"code :#include ...","input :cpu_limit mem_limit"}
    //out_json {"status :0","reason: ","stdout :","stderr"}
        static std::string CodeToDesc(int code,const std::string&file_name)
        {
            std::string desc;
            switch (code)
            {
            case 0:
            desc="编译运行成功";
                break;

            case -1:
            desc="提交的代码为空";
                 break;

            case -2:
            desc="未知错误";
               break;

            case -3:
            // desc="代码编译时候发生了错误";
            FileUtil::ReadFile(PathUtil::CompileError(file_name),&desc,true);//输出到stderr中了
            break;

            case SIGABRT:
            desc="内存超出范围";
            break;

            case SIGFPE:
            desc="浮点数溢出";
            break;

            default:
            desc="未知："+std::to_string(code);
            break;
            }

            return desc;
        }

        static void Start(const std::string&in_json,std::string * out_json, char *env[])
        {
            Json::Value in_value;//用于存储解析后的json数据
            Json::Reader reader;//解析json的工具
            reader.parse(in_json,in_value);//解析

            std::string code=in_value["code"].asString();
            std::string input=in_value["input"].asString();

            int cpu_limit=in_value["cpu_limit"].asInt();
            int mem_limit=in_value["mem_limit"].asInt();
            std::cout << "mem_limit: " << mem_limit << std::endl;

            int status_code=0;
            Json::Value out_value;//用于存储，回复的json信息
            int run_result=0;
            
            std::string file_name;//用户提交的代码，形成一份源码
            if(code.size()==0)//用户提交的代码为空
            {
                status_code=-1;//代码为空错误
                goto END;
            }

            //有时候会有很多用户访问，有多份代码的提交，所有形成的源文件的名字不能是相同的
            //这个时候的文件名还没有后缀和目录。采用毫秒级时间戳+原子递增，保证唯一性
            file_name=FileUtil::UniqueFileName();  

            //形成临时的src文件
            
            if(!FileUtil::WriteFile(PathUtil::Src(file_name),code))
            {
                status_code=-2;//未知错误,系统的错误。
                goto END;
            }
            
            if(!Compiler::Compile(file_name))
            {
                //编译错误
                status_code=-3;//编译的错误；
                goto END;
            }

            run_result=Runner::Run(file_name,cpu_limit,mem_limit, env);
            if(run_result<0)
            {
                status_code=-2;//未知的错误，系统的错误；
            }
            else if(run_result==0)
            {
                status_code=0;//程序运行完毕了。
            }
            else
            {
                //程序崩溃了，被信号终止了
                status_code=run_result;
            }
        END:
        out_value["status"]=status_code;
        out_value["reason"]=CodeToDesc(status_code,file_name);

        if(status_code==0)
        {
            //形成文件，形成可执行程序，运行完毕，都没有问题
            std::string _stdout;//运行的结果
            FileUtil::ReadFile(PathUtil::Stdout(file_name),&_stdout,true);
            out_value["stdout"]=_stdout;

            //运行反馈的信息
            std::string _stderr;
            FileUtil::ReadFile(PathUtil::Stderr(file_name),&_stderr,true);
            out_value["stderr"]=_stderr;
        }

        Json::StreamWriterBuilder builder;
        builder["emitUTF8"] = true;
        *out_json = Json::writeString(builder,out_value); // 序列化回复信息

        RemoveTempFile(file_name);
        }
    };
};

